package com.mpgame.common.connection;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.Optional;

import com.mpgame.common.utils.ConsulServiceDiscovery;
import com.mpgame.common.utils.Log;

/**
 * 根据需要延迟从 Consul 获取服务地址并创建连接池。
 * 若服务地址变化，可调用 forceRefresh 触发重建。
 */
public class DynamicGrpcPoolProvider {

    private final ConsulServiceDiscovery discovery;
    private final ConcurrentMap<String, GrpcConnectionPool> pools = new ConcurrentHashMap<>();

    // 每次成功发现的地址缓存，用于检测地址变化
    private final ConcurrentMap<String, String> lastAddress = new ConcurrentHashMap<>();

    public DynamicGrpcPoolProvider(ConsulServiceDiscovery discovery) {
        this.discovery = discovery;
    }

    public GrpcConnectionPool getPool(String serviceName, int core, int max) {
        // 已有池且地址未变化直接返回
        GrpcConnectionPool existing = pools.get(serviceName);
        if (existing != null) {
            return existing;
        }
        // 尝试发现
        Optional<String> targetOpt = discovery.getService(serviceName);
        if (targetOpt.isEmpty()) {
            Log.warn("服务尚未在 Consul 中注册或无健康实例: " + serviceName);
            return null;
        }
        String target = targetOpt.get();
        // 并发创建
        return pools.computeIfAbsent(serviceName, k -> {
            lastAddress.put(serviceName, target);
            Log.info("创建 gRPC 连接池: " + serviceName + " -> " + target);
            return new GrpcConnectionPool(serviceName, target, core, max);
        });
    }

    /**
     * 若发现地址变化则重建连接池。
     */
    public void refreshIfChanged(String serviceName, int core, int max) {
        Optional<String> targetOpt = discovery.getService(serviceName);
        if (targetOpt.isEmpty()) {
            return;
        }
        String newAddr = targetOpt.get();
        String prev = lastAddress.get(serviceName);
        if (prev == null || !prev.equals(newAddr)) {
            Log.info("检测到服务地址变化，重建连接池: " + serviceName + " " + prev + " -> " + newAddr);
            GrpcConnectionPool old = pools.remove(serviceName);
            if (old != null) {
                try { old.shutdown(); } catch (Exception e) { Log.err("关闭旧连接池失败: " + e.getMessage()); }
            }
            lastAddress.put(serviceName, newAddr);
            pools.put(serviceName, new GrpcConnectionPool(serviceName, newAddr, core, max));
        }
    }

    /**
     * 强制刷新（即使地址未变化也重建）。
     */
    public void forceRefresh(String serviceName, int core, int max) {
        Optional<String> targetOpt = discovery.getService(serviceName);
        if (targetOpt.isEmpty()) {
            Log.warn("forceRefresh 未找到服务: " + serviceName);
            return;
        }
        String newAddr = targetOpt.get();
        GrpcConnectionPool old = pools.remove(serviceName);
        if (old != null) {
            try { old.shutdown(); } catch (Exception e) { Log.err("关闭旧连接池失败: " + e.getMessage()); }
        }
        lastAddress.put(serviceName, newAddr);
        pools.put(serviceName, new GrpcConnectionPool(serviceName, newAddr, core, max));
        Log.info("已强制重建连接池: " + serviceName + " -> " + newAddr);
    }
}
